<template>
    <div class="base-table-container" :style="{ maxHeight: containerHeight }">
        <div class="table-header-wrapper">
            <div class="table-header" ref="headerRef">
                <div class="header-cell" v-for="(column, index) in columns" :key="index" :class="{
                    'fixed-left': column.fixed === 'left',
                    'fixed-right': column.fixed === 'right',
                    'last-column': index === columns.length - 1 && !column.width
                }" :style="{
                    width: getColumnWidth(column, index),
                    textAlign: column.align || 'left',
                    left: column.fixed === 'left' ? getFixedLeftPosition(index) + 'px' : 'auto',
                    right: column.fixed === 'right' ? getFixedRightPosition(index) + 'px' : 'auto'
                }">
                    {{ column.title }}
                </div>
            </div>
        </div>
        <div class="table-body-wrapper" ref="bodyWrapperRef" @scroll="handleScroll">
            <div class="table-body" ref="bodyRef">
                <div v-for="(row, rowIndex) in data" :key="rowIndex"
                    :class="['table-row', (bgActive == row[bgActiveProp] ? ' bg-active' : '')]">
                    <div class="body-cell" v-for="(column, colIndex) in columns" :key="colIndex" :class="{
                        'fixed-left': column.fixed === 'left',
                        'fixed-right': column.fixed === 'right',
                        'last-column': colIndex === columns.length - 1 && !column.width,
                    }" :style="{
                        width: getColumnWidth(column, colIndex),
                        textAlign: column.align || 'left',
                        left: column.fixed === 'left' ? getFixedLeftPosition(colIndex) + 'px' : 'auto',
                        right: column.fixed === 'right' ? getFixedRightPosition(colIndex) + 'px' : 'auto'
                    }" :title="column.render ? column.render(row, column, rowIndex) : row[column.prop]">
                        <slot v-if="column.slot" :name="`column-${column.prop}`" :row="row" :index="rowIndex"></slot>
                        <template v-else>
                            {{ column.render ? column.render(row, column, rowIndex) : row[column.prop] }}
                        </template>
                    </div>
                </div>
                <div class="loading-more" v-if="loading">
                    <slot name="loading">
                        <div class="default-loading flex_row">
                            <i class="el-icon-loading" style="font-size: 14px;"></i>
                            <span class="ml5">加载中</span>
                        </div>
                    </slot>
                </div>
                <div class="no-more" v-if="!hasMore && data.length > 0">
                    <slot name="noMore">
                        <div class="default-no-more">没有更多数据了</div>
                    </slot>
                </div>
                <div class="empty-data" v-if="!loading && noData">
                    <slot name="empty">
                        <div class="default-empty">暂无数据</div>
                    </slot>
                </div>
            </div>
        </div>
    </div>

</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, computed, watch, reactive, nextTick } from '@vue/composition-api'

const props = defineProps({
    // 表头数据
    columns: {
        type: Array,
        required: true,
        validator: (value) => {
            return value.every(col => col.title && col.prop)
        }
    },
    // 列表数据
    data: {
        type: Array,
        default: () => []
    },
    // 表格高度
    height: {
        type: [String, Number],
        default: 'auto'
    },
    // 是否还有更多数据
    hasMore: {
        type: Boolean,
        default: true
    },
    // 是否正在加载
    loading: {
        type: Boolean,
        default: false
    },
    // 加载更多距离
    loadDistance: {
        type: Number,
        default: 50
    },
    // 激活当前行的标识符
    bgActive: {
        type: [String, Number, Boolean],
        default: ''
    },
    // 激活当前行根据列表那个 key 值
    bgActiveProp: {
        type: String,
        default: ''
    }
})

const emit = defineEmits(['load-more'])
const headerRef = ref(null)
const bodyRef = ref(null)
const bodyWrapperRef = ref(null)
const headerHeight = ref(40)
const noData = ref(false)
const columnWidths = ref({})
const isFirstLoad = ref(true)

const containerHeight = computed(() => {
    if (props.data.length > 0) {
        return `${props.height}px`
    } else {
        return '100px'
    }
})

// 监听loading状态变化
watch(() => props.loading, (newVal) => {
    if (!newVal) {
        isFirstLoad.value = false
    }
}, { immediate: true, deep: true })

// 监听数据变化
watch(() => props.data, (newVal) => {
    if (newVal.length > 0) {
        // 等待DOM更新后计算宽度
        nextTick(() => {
            calculateColumnWidths()
        })
    }
    // 只有在非首次加载且数据为空时才显示暂无数据
    if (!isFirstLoad.value && newVal.length == 0) {
        noData.value = true
    } else {
        noData.value = false
    }
}, { immediate: true, deep: true })

onMounted(() => {
    if (headerRef.value) {
        headerHeight.value = headerRef.value.offsetHeight
    }
})

const handleScroll = (e) => {
    if (props.loading || !props.hasMore) return

    // 同步水平滚动
    if (headerRef.value && bodyWrapperRef.value) {
        const scrollLeft = bodyWrapperRef.value.scrollLeft
        // 只移动非固定列
        const nonFixedColumns = props.columns.filter(col => !col.fixed)
        let translateX = 0
        let currentWidth = 0

        for (let i = 0; i < props.columns.length; i++) {
            const col = props.columns[i]
            if (!col.fixed) {
                currentWidth += parseInt(col.width) || 100
                if (currentWidth <= scrollLeft) {
                    translateX = currentWidth
                }
            }
        }
        headerRef.value.style.transform = `translateX(-${translateX}px)`
    }

    // 处理垂直滚动加载更多
    const target = bodyWrapperRef.value
    if (!target) return
    const { scrollTop, scrollHeight, clientHeight } = target
    const distanceToBottom = scrollHeight - (scrollTop + clientHeight)
    if (distanceToBottom <= props.loadDistance) {
        emit('load-more')
    }
}

// 计算固定列的左侧位置
const getFixedLeftPosition = (index) => {
    let position = 0
    for (let i = 0; i < index; i++) {
        if (props.columns[i].fixed === 'left') {
            position += parseInt(props.columns[i].width) || 100
        }
    }
    return position
}

// 计算固定列的右侧位置
const getFixedRightPosition = (index) => {
    let position = 0
    for (let i = props.columns.length - 1; i > index; i--) {
        if (props.columns[i].fixed === 'right') {
            position += parseInt(props.columns[i].width) || 100
        }
    }
    return position
}

// 计算每列的实际宽度
const calculateColumnWidths = () => {
    if (!bodyRef.value) return

    const rows = bodyRef.value.querySelectorAll('.table-row')
    if (rows.length === 0) return

    const newWidths = {}
    let totalFixedWidth = 0
    let lastColumnIndex = -1

    // 第一遍：计算固定宽度和找到最后一列
    props.columns.forEach((column, colIndex) => {
        if (column?.width) {
            totalFixedWidth += parseInt(column.width)
        } else {
            lastColumnIndex = colIndex
        }
    })

    // 第二遍：设置宽度
    props.columns.forEach((column, colIndex) => {
        if (column?.width) {
            newWidths[column.prop] = parseInt(column.width)
        } else if (colIndex === lastColumnIndex) {
            // 最后一列使用剩余宽度
            newWidths[column.prop] = 'auto'
        } else {
            let maxWidth = 0
            rows.forEach(row => {
                const cell = row.children[colIndex]
                if (cell) {
                    const width = cell.offsetWidth
                    maxWidth = Math.max(maxWidth, width)
                }
            })
            newWidths[column.prop] = Math.max(maxWidth, 100)
        }
    })

    columnWidths.value = newWidths
}

// 获取列宽
const getColumnWidth = (column, index) => {
    // 优先使用手动设置的宽度
    if (column?.width) {
        return column.width
    }
    // 如果是最后一列且没有设置宽度，则使用flex: 1
    if (index === props.columns.length - 1 && !column?.width) {
        return 'auto'
    }
    // 其他情况使用计算出的宽度
    const calculatedWidth = columnWidths.value[column.prop]
    return calculatedWidth ? `${calculatedWidth}px` : '100px'
}


</script>

<style scoped lang="scss">
.base-table-container {
    width: 100%;
    // height: 100%;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border: 1px solid #ebeef5;
    border-radius: 4px;
    position: relative;
}

.table-header-wrapper {
    position: relative;
    background-color: #f8f8f9;
    border-bottom: 1px solid #ebeef5;
    z-index: 2;
    width: 100%;
}

.table-header {
    display: flex;
    width: 100%;
    font-weight: bold;
    color: #333;
    position: relative;
    z-index: 1;
    will-change: transform;
}

.header-cell {
    flex-shrink: 0;
    padding: 5px 8px;
    box-sizing: border-box;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    border-right: 1px solid #ebeef5;
    position: relative;
    z-index: 1;

    &.fixed-left {
        position: sticky;
        z-index: 3;
        background-color: #f8f8f9;
    }

    &.fixed-right {
        position: sticky;
        z-index: 3;
        background-color: #f8f8f9;
    }

    &.last-column {
        flex: 1;
        flex-shrink: 1;
    }
}

.header-cell:last-child {
    border-right: none;
}

.table-body-wrapper {
    flex: 1;
    overflow: auto;
    position: relative;
    width: 100%;
}

.table-body {
    width: 100%;
}

.table-row {
    display: flex;
    width: 100%;
    border-bottom: 1px solid #ebeef5;
    transition: background-color 0.25s;
    position: relative;
}

.table-row:last-child {
    border-bottom: none;
}

.table-row:hover {
    background-color: #f5f7fa;
}

.body-cell {
    flex-shrink: 0;
    padding: 5px 8px;
    box-sizing: border-box;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    border-right: 1px solid #ebeef5;
    position: relative;
    z-index: 1;
    cursor: default;

    &.fixed-left {
        position: sticky;
        z-index: 2;
        background-color: #fff;
    }

    &.fixed-right {
        position: sticky;
        z-index: 2;
        background-color: #fff;
    }

    &.last-column {
        flex: 1;
        flex-shrink: 1;
    }
}

.body-cell:last-child {
    border-right: none;
}

.loading-more,
.no-more,
.empty-data {
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 6px 10px;
    color: #909399;
}

.bg-active {
    background-color: rgba(139, 182, 238, 0.4) !important;
}
</style>